package com.ziiwee.reduce.describe.creators.types;

import com.ziiwee.reduce.commons.utils.BeanUtil;
import com.ziiwee.reduce.describe.AbstractDescribe;
import com.ziiwee.reduce.describe.FieldDescribe;
import com.ziiwee.reduce.describe.TypeDescribe;
import com.ziiwee.reduce.describe.creators.TypeDescribeCreator;
import com.ziiwee.reduce.describe.creators.fields.DefaultFieldDescribeCreator;
import com.ziiwee.reduce.describe.models.TypeDescribeModel;
import com.ziiwee.reduce.describe.utils.DescribeUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ResolvableType;

import java.beans.PropertyDescriptor;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author ziiwee
 * @data 2020/8/12
 */
public class DefaultTypeDescribeCreator extends AbstractDescribe implements TypeDescribeCreator, TypeDescribe {

    private final Log log = LogFactory.getLog(getClass());

    private final ResolvableType type;

    public DefaultTypeDescribeCreator(ResolvableType type) {
        this.type = type;
    }

    @Override
    public AnnotatedElement getElement() {
        return type.resolve();
    }

    @Override
    public ResolvableType getDefaultType() {
        return type;
    }

    @Override
    public List<FieldDescribe> getFields() {
        List<FieldDescribe> list = new ArrayList<>();
        Class<?> cls = Objects.requireNonNull(type.resolve());
        for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(cls)) {
            try {
                Field field = BeanUtil.getField(cls, pd.getName());
                if (field != null) {
                    list.add(new DefaultFieldDescribeCreator(field).create());
                }
            } catch (Exception e) {
                log.warn(e.getMessage());
            }
        }
        return list;
    }

    @Override
    public String getName() {
        return DescribeUtil.getSimpleNameByResolvableType(type);
    }

    @Override
    public TypeDescribe create() {
        return new TypeDescribeModel(getName(), getType(), getLabel(), getDescription(), getFields());
    }
}
